using UnityEngine;
using System.Collections.Generic;
#if UNITY_EDITOR
using UnityEditor;
#endif

public class PoolManager : Singleton<PoolManager>
{
	public PoolInfo[] startingPool;

	private Transform poolContainer;
	private Dictionary<string, GameObject> prefabs = new Dictionary<string, GameObject>();
	private Dictionary<string, List<GameObject>> pool = new Dictionary<string, List<GameObject>>();

	private void Awake()
	{
		poolContainer = new GameObject("PoolContainer").transform;
		poolContainer.parent = transform;
		foreach (PoolInfo info in startingPool)
		{
			AddToPool(info.prefab, info.qtyPool);
		}
	}

	public void CreatePool(GameObject _prefab, int _qty = 5)
	{
		if (!pool.ContainsKey(_prefab.name))
		{
			AddToPool(_prefab, _qty);
		}
	}
	
	public void AddToPool(GameObject _prefab, int _qty = 1)
	{
		if (!pool.ContainsKey(_prefab.name))
		{
			pool.Add(_prefab.name, new List<GameObject>());
		}
		
		if (!prefabs.ContainsKey(_prefab.name))
		{
			prefabs.Add(_prefab.name, _prefab);
		}
		
		for (int i = 0; i < _qty; i++)
		{
			pool[_prefab.name].Add(SpawnObject(_prefab));
		}
	}
	
	public void AddToPool(GameObject[] _prefabs, int _qty = 1)
	{
		foreach (GameObject go in _prefabs)
		{
			AddToPool(go, _qty);
		}
	}

	public void ReturnToPool(GameObject _obj)
	{
		if (pool.ContainsKey(_obj.name))
		{
			_obj.SendMessage("PoolDisable", SendMessageOptions.DontRequireReceiver);
			_obj.transform.SetParent(poolContainer);
			_obj.transform.localPosition = Vector3.one * 1000f;
			_obj.SetActive(false);

			if (!pool[_obj.name].Contains(_obj))
			{
				pool[_obj.name].Add(_obj);
			}
		}
		else
		{
			Debug.LogError("Object of name " + _obj.name + " was not in pool");
		}
	}

	public GameObject GetFromPool(string _name)
	{
		GameObject obj = GetFromPool(_name, Vector3.zero, Quaternion.identity);
		obj.SendMessage("PoolEnable", SendMessageOptions.DontRequireReceiver);
		return obj;
	}

	public GameObject GetFromPool(string _name, Vector3 _pos, Quaternion _rot)
	{
		GameObject obj = null;
		if (pool.ContainsKey(_name))
		{
			if (pool[_name].Count > 0)
			{
				obj = pool[_name][0];
				pool[_name].RemoveAt(0);
			}
			else
			{
				obj = SpawnObject(prefabs[_name]);
			}

			obj.transform.SetParent(null);
			obj.transform.position = _pos;
			obj.transform.rotation = _rot;
			obj.SetActive(true);
		}
		else
		{
			Debug.LogError("Object of name " + _name + " was not in pool");
		}
		
		return obj;
	}

	// TODO : Get object from pool and set parent
	/*public GameObject GetFromPool(string _name, Transform _parent = null)
	{

	}*/

	private GameObject SpawnObject(GameObject _prefab)
	{
		GameObject newObj = Instantiate(_prefab) as GameObject;
		newObj.name = _prefab.name;
		newObj.transform.SetParent(poolContainer);
		newObj.transform.localPosition = Vector3.one * 1000f;
		newObj.SetActive(false);

		return newObj;
	}

	[System.Serializable]
	public class PoolInfo
	{
		public GameObject prefab = null;
		public int qtyPool = 5;
	}

#if UNITY_EDITOR
	[CustomPropertyDrawer(typeof(PoolInfo))]
	public class PoolInfoDrawer : PropertyDrawer
	{
		public override void OnGUI (Rect position, SerializedProperty property, GUIContent label)
		{
			Rect rect = new Rect(position);

			rect.width = 75f;
			EditorGUI.LabelField(rect, "Prefab");

			rect.x += rect.width - 10f;
			rect.width = Screen.width * 0.5f;
			EditorGUI.PropertyField(rect, property.FindPropertyRelative("prefab"), GUIContent.none);

			rect.x += rect.width - 10f;
			rect.width = 50f;
			EditorGUI.LabelField(rect, "Qty");

			rect.x += rect.width - 10f;
			rect.width = Screen.width * 0.25f;
			EditorGUI.PropertyField(rect, property.FindPropertyRelative("qtyPool"), GUIContent.none);
		}
	}
#endif
}
